#include <iostream>
#include <fstream>
#include "contacts.pb.h"
#include "contacts.pb.cc" // 是不是一旦引入这个文件就报错

using namespace std;
using namespace contacts;

// 向contacts中添加内容的函数
// 关于传入参数为: contacts.contacts_add()函数的返回值
// repeted修饰的字段名才有 xxx_add()方法 ？ ？ ？
void AddPeopleInfo(PeopleInfo *people_info_ptr)
{
    cout << "新增联系人:" << endl;
    cout << "name:";
    string name;
    getline(cin, name); // ？ ？ ？
    people_info_ptr->set_name(name);

    cout << "age :";
    int age;
    cin >> age;
    people_info_ptr->set_age(age);
    // cin.ignore(256, '\n'); 是C++中的一个输入流操作函数。
    // 它的作用是忽略输入流中的一定数量的字符，直到遇到指定的终止字符（在这里是换行符'\n'）为止。
    cin.ignore(256, '\n');

    for (int i = 0;; i++)
    {
        cout << "phone :" << i << "(只输⼊回⻋完成电话新增)";
        string number;
        getline(cin, number); // getline默认读到/n结束
        if (number.empty())
        {
            break;
        }

        // 消息Phone在PeopleIfo中定义，所以是PeopleInfo_Phone格式 ！！！！
        PeopleInfo_Phone *phone = people_info_ptr->add_phone();
        phone->set_number(number);

        // 枚举————电话类型
        cout << "Select a phone type : mobile---press 1  ,  immobile ---press 2" << endl;
        int type;
        cin >> type;
        cin.ignore(256, '\n');
        switch (type)
        {
        case 1:

            phone->set_type(PeopleInfo_Phone_TypePhone::PeopleInfo_Phone_TypePhone_MP);
            break;

        case 2:

            phone->set_type(PeopleInfo_Phone_TypePhone::PeopleInfo_Phone_TypePhone_TEL);
            break;

        default:

            cout << "error select , use mobile type";
            break;
        }

     /*  //如果使用Any类型
     Address address;
     cout << "请输⼊联系⼈家庭地址: ";
     string home_address;
     getline(cin, home_address);
     address.set_home_address(home_address);
     cout << "请输⼊联系⼈单位地址: ";
     string unit_address;
     getline(cin, unit_address);
     address.set_unit_address(unit_address);
     google::protobuf::Any * data = people_info_ptr->mutable_data();
     data->PackFrom(address);*/
        
        cout << "Select a contact method : QQ---press 1 , WeChat---press 2 " << endl ; 
        int other_contact ; 
        cin >> other_contact ; 
        cin.ignore(256, '\n') ; // ? ? 
        if(1 == other_contact)
        {
            cout << "input QQ :" ; 
            string qq ; 
            getline(cin, qq) ; 
            people_info_ptr->set_qq(qq);
        }
        else if( 2 == other_contact)
        {
            cout << "input WeChat :" ; 
            string wechat ; 
            getline(cin, wechat) ;
            people_info_ptr->set_weixin(wechat);
        }
        else 
        {
            cout << "error : Please select thr right option " << endl ; 
        }



    } 

    cout << "jion success !" << endl;
}

int main(int argc, char *agrv[])
{
    // 检测main函数参数
    if (argc != 2)
    {
        cerr << "Usage:" << agrv[0] << "CONTACTS_FILE" << endl;
        return -1;
    }
    // GOOGLE_PROTOBUF_VERIFY_VERSION 宏: 验证没有意外链接到与编译的头⽂件不兼容的库版
    // 本。如果检测到版本不匹配，程序将中⽌。注意，每个 .pb.cc ⽂件在启动时都会⾃动调⽤此宏。在使
    // ⽤ C++ Protocol Buffer 库之前执⾏此宏是⼀种很好的做法，但不是绝对必要的。
    // GOOGLE_PROTOBUF_VERIFY_VERSION;

    // 创建消息对像
    Contacts contacts;

    // 读取文件中内容
    // argv[1]为指定打开的文件名
    // 输入模式 + 二进制模式
    fstream input(agrv[1], ios::in | ios::binary);
    if (!input)
    {
        cout << agrv[1] << ": file not find " << endl;
        return -1;
    }
    else if (!contacts.ParseFromIstream(&input)) // ParseFromIstream() !!!!
    {
        cerr << "Faild to parse contacts ." << endl;
        input.close();
        return -1;
    }

    // 向message中添加
    AddPeopleInfo(contacts.add_contacts()); // 定义在开头

    // 向文件中添加新的内容

    fstream output(agrv[1], ios::out | ios::binary | ios::trunc);
    if (!output)
    {
        cout << agrv[1] << ": open failed ";
    }

    if (!contacts.SerializeToOstream(&output)) // Ostream? ? ?
    {
        cerr << agrv[1] << ": failed write in ";
        output.close();
        return -1;
    }

    input.close();
    output.close();
    // 在程序结束时调⽤ ShutdownProtobufLibrary()，为了删除 Protocol Buffer 库分配的所
    // 有全局对象。对于⼤多数程序来说这是不必要的，因为该过程⽆论如何都要退出，并且操作系统将负责
    // 回收其所有内存。但是，如果你使⽤了内存泄漏检查程序，该程序需要释放每个最后对象，或者你正在
    // 编写可以由单个进程多次加载和卸载的库，那么你可能希望强制使⽤ Protocol Buffers 来清理所有
    // 内容。
    // google::protobuf::ShutdownProtobufLibrary();

    return 0;
}

// 编译指令: g++ -o write write.cpp -std=c++11 -lprotobuf -pthread
//  -pthread 一定要加 不然报错 ;
// 运行指令: ./write contacts.bin
// 是否运行成功: 用二进制转化工具查看contacts.bin中的内容

/*int main()
{
    Contacts contacts ;

    return 0 ;
}*/